use std::boxed::Box;

struct MyStruct {
    x: i32,
}

trait Draw {
    fn draw(&self);
}

struct Circle {
    radius: i32,
}

impl Draw for Circle {
    fn draw(&self) {
        println!("Drawing a circle with radius {}", self.radius);
    }
}

struct Square {
    side: i32,
}

impl Draw for Square {
    fn draw(&self) {
        println!("Drawing a square with side {}", self.side);
    }
}

fn draw_shapes(shapes: &[Box<dyn Draw>]) {
    for shape in shapes {
        shape.draw();
    }
}

// Box<dyn Draw> 类型擦除
fn test() {
    let circle = Box::new(Circle { radius: 5 });
    let square = Box::new(Square { side: 10 });

    let shapes: Vec<Box<dyn Draw>> = vec![circle, square];

    draw_shapes(&shapes);
}

// 递归类型
enum List {
    Cons(i32, Box<List>),
    Nil,
}

fn print_list(list: &List) {
    match list {
        List::Cons(value, next) => {
            println!("{}", value);
            print_list(next);
        },
        List::Nil => {},
    }
}

fn test_list() {
    let list = List::Cons(1, Box::new(List::Cons(2, Box::new(List::Cons(3, Box::new(List::Nil))))));
    print_list(&list);
}

fn main() {
    let x = Box::new(5);
    println!("x: {}, *x: {}", x, *x);
    assert_eq!(*x, 5);

    let y = Box::new(MyStruct { x: 10 });
    println!("y.x: {}", y.x);

    test();
    test_list();
}
